package com.ydj.framework.mysql.generator;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * 统一处理mongo的ID生层，包含统一生成UID，还有生成自增Id
 * @author rick
 */
@Component
@Slf4j
public class SnowFlakeIdUtils {
    private static final int INDEX_BIT = 3;

    private static final int INDEX_MAX_LENGTH = (int) Math.pow(10, INDEX_BIT);
    private static final int INDEX_MAX = INDEX_MAX_LENGTH - 1;

    /** 2020-01-01 */
    private static final long RELATIVE_TIME = 1577808000000L;
    private static final byte[] LOCK = new byte[0];
    private static int index = 0;

    /** 容器ID(当做机器ID也可以) */
    private Long machineId;
    private int machineIdLength;

    @Autowired
    private StringRedisTemplate redisTemplate;

    public synchronized long generatorId() {
        if (machineId == null) {
            regMachine();
        }

        long now = (System.currentTimeMillis() - RELATIVE_TIME) / 1000;

        index++;
        if (index > INDEX_MAX) {
            index = 0;
        }

        long ret = now;
        ret = ret * machineIdLength + machineId;
        ret = ret * INDEX_MAX_LENGTH + index;

        return ret;
    }

    private void regMachine() {
        String lua = "local id_key = KEYS[1]\n" +
                "local current = redis.call('get',id_key)\n" +
                "if current == false or tonumber(current) >= tonumber(ARGV[1]) then\n" +
                "    redis.call('set',id_key,1)\n" +
                "    return 1\n" +
                "end\n" +
                "local result = tonumber(current)+1\n" +
                "redis.call('set',id_key,result)\n" +
                "return result";
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(lua,Long.class);
        // 参数一：redisScript，参数二：key列表，参数三：arg（可多个）

        List<String> keys = new ArrayList<>();
        keys.add("MachineId");
        Object[] argv = {"999"};

        machineId = redisTemplate.execute(redisScript, keys, argv);
        machineIdLength = (int) Math.pow(10, String.valueOf(machineId).length());
    }

}